/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bff.core.manager;

import com.inspur.edp.bef.api.lcp.ILcpFactory;
import com.inspur.edp.bef.api.lcp.IStandardLcp;
import com.inspur.edp.bff.api.attribute.AbstractSourceConfig;
import com.inspur.edp.bff.api.dataprocessor.IChangeConvertor;
import com.inspur.edp.bff.api.dataprocessor.IDataConvertor;
import com.inspur.edp.bff.api.dataprocessor.IDefaultValueConvertor;
import com.inspur.edp.bff.api.dataprocessor.IEntityPropertyMapper;
import com.inspur.edp.bff.api.dataprocessor.IFilterFieldConvertor;
import com.inspur.edp.bff.api.exception.BffFrameworkException;
import com.inspur.edp.bff.api.exception.ErrorCodes;
import com.inspur.edp.bff.api.extend.IBffManagerExtend;
import com.inspur.edp.bff.api.manager.IFSAction;
import com.inspur.edp.bff.api.manager.IFSManager;
import com.inspur.edp.bff.api.manager.IFSManagerContext;
import com.inspur.edp.bff.api.manager.SourceConfig;
import com.inspur.edp.bff.api.manager.SourceType;
import com.inspur.edp.bff.api.manager.assembler.IAssemblerManager;
import com.inspur.edp.bff.spi.AbstractDataConvertor;
import com.inspur.edp.bff.spi.AbstractFSAction;
import com.inspur.edp.bff.spi.utils.AuthUtils;
import com.inspur.edp.cef.api.changeListener.EntityDataChangeListener;
import com.inspur.edp.cef.api.manager.action.IMgrActionExecutor;
import com.inspur.edp.cef.api.session.ICefSessionItem;
import com.inspur.edp.cef.core.rootmanager.BaseRootManagerContext;
import com.inspur.edp.cef.entity.changeset.IChangeDetail;
import com.inspur.edp.cef.entity.entity.ICefData;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.spi.entity.resourceInfo.EntityResInfo;
import com.inspur.edp.cef.spi.entity.resourceInfo.ModelResInfo;
import io.iec.edp.caf.runtime.config.CefBeanUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FSManagerContext extends BaseRootManagerContext implements IFSManagerContext {

    private FSManager manager;
    private IAssemblerManager assemblerManager;
    private String sessionId;
    private String voId;
    private EntityDataChangeListener varListener;
    private ICefData variableData;
    private ILcpFactory lcpFactory;
    private boolean useAuth = true;

    public FSManagerContext(FSManager manager) {
        this.manager = manager;
        assemblerManager = this.manager.getAssemblerManager();
    }

    public final IAssemblerManager getAssemblerManager() {
        return assemblerManager;
    }

    public IFSManager getBffManager() {
        return manager;
    }

    public final IEntityData createData() {
        return manager.innerCreateData();
    }

    public final IEntityData createData(String objectCode) {
        return manager.innerCreateChildData(objectCode);
    }

    public final <TResult> TResult executeAction(IFSAction<TResult> action) {
        return ActionExecutor.executeAction((AbstractFSAction<TResult>) action, manager, this);
    }

    @Override
    public <TResult> TResult executeAction(IFSAction<TResult> action, String actionId, String actionCode, Map<String, Object> parameters) {
        return this.executeAction(action, actionId, actionCode, parameters, false);
    }

    @Override
    public <TResult> TResult executeAction(IFSAction<TResult> action, String actionId, String actionCode, Map<String, Object> parameters, boolean autoSave) {
        return ActionExecutor.executeAction((AbstractFSAction<TResult>) action, manager, this, actionId, actionCode, parameters, autoSave);
    }

    public final void processResponse() {
        ActionExecutor.processResponse(manager, this);
    }

    public final String getBECodeFromVM(String vmObjectCode) {
        return manager.getBECodeFromVM(vmObjectCode);
    }

    public final String getVoId() {
        return voId;
    }

    public final void setVoId(String value) {
        voId = value;
    }

    public boolean isUseAuth() {
        return useAuth;
    }

    public void setUseAuth(boolean useAuth) {
        this.useAuth = useAuth;
    }

    public final IChangeDetail getVariableInnerChange() {
        if (varListener == null) {
            return null;
        }
        IChangeDetail rez = varListener.getChange();
        varListener.clear();
        return rez;
    }

    @Override
    public String getVoCode(String frontVoCode) {
        return manager.getVoNodeCode(frontVoCode);
    }

    public final ICefData getVariableData() {
        if (variableData == null) {
            variableData = manager.getVariableData();
            varListener = manager.getVariableListener();
        }
        return variableData;
    }

    public final IChangeConvertor getChangeConvertor() {
        return manager.getChangeMapConvertor();
    }

    @Override
    public final IEntityPropertyMapper getRootEntityPropertyMapper() {
        return manager.getRootEntityPropertyMapper();
    }

    public final IDataConvertor getDataConvertor() {

        AbstractDataConvertor dataConvertor = (AbstractDataConvertor) manager.getDataConvertor();
        if (dataConvertor == null)
            throw new BffFrameworkException(ErrorCodes.BFF_FRAMEWORK_1037);
        dataConvertor.setFSManager(this.getBffManager());
        return dataConvertor;
    }

    public final IFilterFieldConvertor getFilterConvertor() {
        return manager.getFilterConvertor();
    }

    public final IDefaultValueConvertor getDefaultValueConvertor() {
        return manager.getDefaultValueConvertor();
    }

    public final HashMap<String, IStandardLcp> getLcps() {
        HashMap<String, IStandardLcp> lcps = new HashMap<String, IStandardLcp>();
        if (manager.getOutSourceConfigs() != null && getSourceConfigs() != null && getSourceConfigs().size() > 0) {
            for (SourceConfig sourceConfig : getSourceConfigs()) {
                if (sourceConfig.getSourceType() == SourceType.Qo || DotNetToJavaStringHelper.isNullOrEmpty(sourceConfig.getSourceConfigId())) {
                    continue;
                }
                IStandardLcp lcp = getLcp(sourceConfig.getSourceConfigId());
                lcp.getBefContext().setEnableTimeStampLastModifiedBy(getBffManager().getTimeStampContext().isEnableTimeStampLastModifiedBy());
                lcps.put(sourceConfig.getSourceConfigId(), lcp);
            }
        }
        return lcps;
    }

    private ILcpFactory getLcpFactory() {
        if (lcpFactory == null) {
            lcpFactory = CefBeanUtil.getAppCtx().getBean(ILcpFactory.class);
        }
        return lcpFactory;
    }

    private IStandardLcp getLcp(String configId) {
        IStandardLcp lcp = getLcpFactory().createLcp(configId);
        if (useAuth) {
            AuthUtils.buildAuthInfo(
                    lcp.getBefContext().getAuthInfo(),
                    getModelResourceInfo(),
                    getVoId(),
                    configId
            );
        } else {
            AuthUtils.buildAuthInfo(
                    lcp.getBefContext().getAuthInfo(),
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null
            );
        }
        return lcp;
    }

    public ICefSessionItem getSessionItem() {
        return manager.getCessionItem();
    }

    public ArrayList<SourceConfig> getSourceConfigs() {
        AbstractSourceConfig sourceConfigs = manager.getOutSourceConfigs();
        return sourceConfigs == null ? null : sourceConfigs.getSourceConfigs();
    }

    public final IStandardLcp getLcp() {
        String beType;
        ArrayList<SourceConfig> sourceConfigs = getSourceConfigs();
        if (sourceConfigs == null || sourceConfigs.size() == 0) {
            throw new BffFrameworkException(ErrorCodes.BFF_FRAMEWORK_1038);
        }
        beType = getSourceConfigs().get(0).getSourceConfigId();
        if (DotNetToJavaStringHelper.isNullOrEmpty(beType)) {
            return null;
        }

        IStandardLcp lcp = getLcp(beType);
        lcp.getBefContext().setEnableTimeStampLastModifiedBy(getBffManager().getTimeStampContext().isEnableTimeStampLastModifiedBy());
        return lcp;
    }

    public final String getVMCodeFromBE(String beObjectCode) {
        return manager.getVMCodeFromBE(beObjectCode);
    }

    public SourceType getMainSourceType() {
        return manager.getOutSourceConfigs().getSourceConfigs().get(0).getSourceType();
    }

    public final <T> IMgrActionExecutor<T> GetActionExecutor() {
        throw new BffFrameworkException();
    }

    public boolean getIsBeforeSaving() {
        return getLcp().getBefContext().getBefStatus().getIsBeforeSaving();
    }

    // region i18n
    public ModelResInfo getModelResourceInfo() {
        return manager.getModelInfo();
    }

    @Override
    public String getEntityI18NName(String nodeCode) {

        return getEntityResourceInfo(nodeCode).getDisplayName();
    }

    @Override
    public String getPropertyI18NName(String nodeCode, String labelID) {

        String result = getEntityResourceInfo(nodeCode).getPropertyDispalyName(labelID);
        if (DotNetToJavaStringHelper.isNullOrEmpty(result)) {
            result = labelID;
        }
        return result;
    }

    @Override
    public String getRefPropertyI18NName(String nodeCode, String labelID, String refLabelID) {
        return getEntityResourceInfo(nodeCode).getAssoRefPropertyDisplay(labelID, refLabelID);
    }

    @Override
    public String getEnumValueI18NDisplayName(String nodeCode, String labelID, String enumKey) {
        return getEntityResourceInfo(nodeCode).getEnumPropertyDispalyValue(labelID, enumKey);
    }


    public final EntityResInfo getEntityResourceInfo(String nodeCode) {
        return getModelResourceInfo().getCustomResource(nodeCode);
    }

    public final String getUniqueConstraintMessage(String nodeCode, String conCode) {
        return getEntityResourceInfo(nodeCode).getUniqueConstraintMessage(conCode);
    }

    public List<IBffManagerExtend> getExtList() {
        return manager.getExtList();
    }

    // endregion
//----------------------------------------------------------------------------------------
//	Copyright © 2006 - 2010 Tangible Software Solutions Inc.
//	This class can be used by anyone provided that the copyright notice remains intact.
//
//	This class is used to simulate some .NET string functions in Java.
//----------------------------------------------------------------------------------------
    public static final class DotNetToJavaStringHelper {
        //------------------------------------------------------------------------------------
        //	This method replaces the .NET static string method 'IsNullOrEmpty'.
        //------------------------------------------------------------------------------------
        public static boolean isNullOrEmpty(String string) {
            return string == null || string.equals("");
        }

        //------------------------------------------------------------------------------------
        //	This method replaces the .NET static string method 'Join' (2 parameter version).
        //------------------------------------------------------------------------------------
        public static String join(String separator, String[] stringarray) {
            if (stringarray == null)
                return null;
            else
                return join(separator, stringarray, 0, stringarray.length);
        }

        //------------------------------------------------------------------------------------
        //	This method replaces the .NET static string method 'Join' (4 parameter version).
        //------------------------------------------------------------------------------------
        public static String join(String separator, String[] stringarray, int startindex, int count) {
            String result = "";

            if (stringarray == null)
                return null;

            for (int index = startindex; index < stringarray.length && index - startindex < count; index++) {
                if (separator != null && index > startindex)
                    result += separator;

                if (stringarray[index] != null)
                    result += stringarray[index];
            }

            return result;
        }

        //------------------------------------------------------------------------------------
        //	This method replaces the .NET static string method 'TrimEnd'.
        //------------------------------------------------------------------------------------
        public static String trimEnd(String string, Character... charsToTrim) {
            if (string == null || charsToTrim == null)
                return string;

            int lengthToKeep = string.length();
            for (int index = string.length() - 1; index >= 0; index--) {
                boolean removeChar = false;
                if (charsToTrim.length == 0) {
                    if (Character.isWhitespace(string.charAt(index))) {
                        lengthToKeep = index;
                        removeChar = true;
                    }
                } else {
                    for (int trimCharIndex = 0; trimCharIndex < charsToTrim.length; trimCharIndex++) {
                        if (string.charAt(index) == charsToTrim[trimCharIndex]) {
                            lengthToKeep = index;
                            removeChar = true;
                            break;
                        }
                    }
                }
                if (!removeChar)
                    break;
            }
            return string.substring(0, lengthToKeep);
        }

        //------------------------------------------------------------------------------------
        //	This method replaces the .NET static string method 'TrimStart'.
        //------------------------------------------------------------------------------------
        public static String trimStart(String string, Character... charsToTrim) {
            if (string == null || charsToTrim == null)
                return string;

            int startingIndex = 0;
            for (int index = 0; index < string.length(); index++) {
                boolean removeChar = false;
                if (charsToTrim.length == 0) {
                    if (Character.isWhitespace(string.charAt(index))) {
                        startingIndex = index + 1;
                        removeChar = true;
                    }
                } else {
                    for (int trimCharIndex = 0; trimCharIndex < charsToTrim.length; trimCharIndex++) {
                        if (string.charAt(index) == charsToTrim[trimCharIndex]) {
                            startingIndex = index + 1;
                            removeChar = true;
                            break;
                        }
                    }
                }
                if (!removeChar)
                    break;
            }
            return string.substring(startingIndex);
        }

        //------------------------------------------------------------------------------------
        //	This method replaces the .NET static string method 'Trim' when arguments are used.
        //------------------------------------------------------------------------------------
        public static String trim(String string, Character... charsToTrim) {
            return trimEnd(trimStart(string, charsToTrim), charsToTrim);
        }

        //------------------------------------------------------------------------------------
        //	This method is used for string equality comparisons when the option
        //	'Use helper 'stringsEqual' method to handle null strings' is selected
        //	(The Java String 'equals' method can't be called on a null instance).
        //------------------------------------------------------------------------------------
        public static boolean stringsEqual(String s1, String s2) {
            if (s1 == null && s2 == null)
                return true;
            else
                return s1 != null && s1.equals(s2);
        }

    }
}
